From f64584ba377b78a49c66f6596fc371d4763fe4c7 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 22 Nov 2006 10:31:50 +0000 Subject: [PATCH] [HVM] Fix instruction linear address computation. This helps newer isolinux' graphical boot code (which crashes without this). Signed-off-by: Jan Beulich --- xen/arch/x86/hvm/platform.c | 5 +++-- xen/arch/x86/hvm/svm/svm.c | 19 +++++++++++++++++++ xen/arch/x86/hvm/vmx/vmx.c | 23 +++++++++++++++++++++++ xen/include/asm-x86/hvm/hvm.h | 21 +++++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 777f2f3c93..10179c2864 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -895,9 +895,10 @@ void handle_mmio(unsigned long gpa) realmode = hvm_realmode(v); if ( realmode ) - inst_addr = (regs->cs << 4) + regs->eip; + inst_addr = regs->cs << 4; else - inst_addr = regs->eip; + inst_addr = hvm_get_segment_base(current, seg_cs); + inst_addr += regs->eip; memset(inst, 0, MAX_INST_LEN); if ( inst_copy_from_guest(inst, inst_addr, inst_len) != inst_len ) { diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 411a056349..455bdac52e 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -510,6 +510,24 @@ unsigned long svm_get_ctrl_reg(struct vcpu *v, unsigned int num) return 0; /* dummy */ } +static unsigned long svm_get_segment_base(struct vcpu *v, enum segment seg) +{ + switch ( seg ) + { + case seg_cs: return v->arch.hvm_svm.vmcb->cs.base; + case seg_ds: return v->arch.hvm_svm.vmcb->ds.base; + case seg_es: return v->arch.hvm_svm.vmcb->es.base; + case seg_fs: return v->arch.hvm_svm.vmcb->fs.base; + case seg_gs: return v->arch.hvm_svm.vmcb->gs.base; + case seg_ss: return v->arch.hvm_svm.vmcb->ss.base; + case seg_tr: return v->arch.hvm_svm.vmcb->tr.base; + case seg_gdtr: return v->arch.hvm_svm.vmcb->gdtr.base; + case seg_idtr: return v->arch.hvm_svm.vmcb->idtr.base; + case seg_ldtr: return v->arch.hvm_svm.vmcb->ldtr.base; + } + BUG(); + return 0; +} /* Make sure that xen intercepts any FP accesses from current */ static void svm_stts(struct vcpu *v) @@ -821,6 +839,7 @@ int start_svm(void) hvm_funcs.pae_enabled = svm_pae_enabled; hvm_funcs.guest_x86_mode = svm_guest_x86_mode; hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg; + hvm_funcs.get_segment_base = svm_get_segment_base; hvm_funcs.update_host_cr3 = svm_update_host_cr3; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 469c3a28b9..a166d4aa8c 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -501,6 +501,28 @@ static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) return 0; /* dummy */ } +static unsigned long vmx_get_segment_base(struct vcpu *v, enum segment seg) +{ + unsigned long base; + + BUG_ON(v != current); + switch ( seg ) + { + case seg_cs: __vmread(GUEST_CS_BASE, &base); break; + case seg_ds: __vmread(GUEST_DS_BASE, &base); break; + case seg_es: __vmread(GUEST_ES_BASE, &base); break; + case seg_fs: __vmread(GUEST_FS_BASE, &base); break; + case seg_gs: __vmread(GUEST_GS_BASE, &base); break; + case seg_ss: __vmread(GUEST_SS_BASE, &base); break; + case seg_tr: __vmread(GUEST_TR_BASE, &base); break; + case seg_gdtr: __vmread(GUEST_GDTR_BASE, &base); break; + case seg_idtr: __vmread(GUEST_IDTR_BASE, &base); break; + case seg_ldtr: __vmread(GUEST_LDTR_BASE, &base); break; + default: BUG(); base = 0; break; + } + return base; +} + /* Make sure that xen intercepts any FP accesses from current */ static void vmx_stts(struct vcpu *v) { @@ -619,6 +641,7 @@ static void vmx_setup_hvm_funcs(void) hvm_funcs.pae_enabled = vmx_pae_enabled; hvm_funcs.guest_x86_mode = vmx_guest_x86_mode; hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; + hvm_funcs.get_segment_base = vmx_get_segment_base; hvm_funcs.update_host_cr3 = vmx_update_host_cr3; diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 2981df13db..c22258460c 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -20,6 +20,19 @@ #ifndef __ASM_X86_HVM_HVM_H__ #define __ASM_X86_HVM_HVM_H__ +enum segment { + seg_cs, + seg_ss, + seg_ds, + seg_es, + seg_fs, + seg_gs, + seg_tr, + seg_ldtr, + seg_gdtr, + seg_idtr +}; + /* * The hardware virtual machine (HVM) interface abstracts away from the * x86/x86_64 CPU virtualization assist specifics. Currently this interface @@ -52,6 +65,7 @@ struct hvm_function_table { * 1) determine whether the guest is in real or vm8086 mode, * 2) determine whether paging is enabled, * 3) return the current guest control-register value + * 4) return the current guest segment descriptor base */ int (*realmode)(struct vcpu *v); int (*paging_enabled)(struct vcpu *v); @@ -59,6 +73,7 @@ struct hvm_function_table { int (*pae_enabled)(struct vcpu *v); int (*guest_x86_mode)(struct vcpu *v); unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num); + unsigned long (*get_segment_base)(struct vcpu *v, enum segment seg); /* * Re-set the value of CR3 that Xen runs on when handling VM exits @@ -161,6 +176,12 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num) return 0; /* force to fail */ } +static inline unsigned long +hvm_get_segment_base(struct vcpu *v, enum segment seg) +{ + return hvm_funcs.get_segment_base(v, seg); +} + void hvm_stts(struct vcpu *v); void hvm_set_guest_time(struct vcpu *v, u64 gtime); void hvm_freeze_time(struct vcpu *v); -- 2.30.2